import re
import time

import pydantic
from fastapi_pagination.bases import AbstractPage
from fastapi_pagination.ext.databases import paginate
from sqlalchemy import select, or_, update

from forward.api.admin.schemas.user import (
    UserListInSchema,
    UserInfoOutSchema,
    UserEditlInSchema,
    UserDetailInSchema,
)
from forward.common.enums import get_login_client, get_sex, SexEnum
from forward.dependencies.database import db
from forward.exceptions.base import AppException
from forward.http_base import HttpResp
from forward.model.tables import UserModel
from forward.utils.urls import UrlUtil


class UserService:
    """用户信息类"""

    async def list(self, list_in: UserListInSchema) -> AbstractPage[UserInfoOutSchema]:
        where = [UserModel.is_delete == 0]
        if list_in.keyword:
            where.append(
                or_(
                    UserModel.username.like("%{0}%".format(list_in.keyword)),
                    UserModel.nickname.like("%{0}%".format(list_in.keyword)),
                    UserModel.mobile.like("%{0}%".format(list_in.keyword)),
                )
            )
        if list_in.channel:
            where.append(UserModel.channel == list_in.channel)
        if list_in.start_time:
            where.append(UserModel.create_time >= list_in.start_time)
        if list_in.end_time:
            where.append(UserModel.create_time <= list_in.end_time)
        query = (
            select(UserModel)
            .select_from(UserModel)
            .where(*where)
            .order_by(UserModel.id.desc())
        )

        user_list_pages = await paginate(db, query)
        for row in user_list_pages.lists:
            row.avatar = await UrlUtil.to_absolute_url(row.avatar)
            row.sex = get_sex(int(row.sex))
            row.channel = get_login_client(int(row.channel))
        return user_list_pages

    async def edit(self, edit_in: UserEditlInSchema):
        assert await db.fetch_one(
            select(UserModel.id)
            .select_from(UserModel)
            .where(UserModel.id == edit_in.id, UserModel.is_delete == 0)
        ), "数据不存在！"

        if edit_in.field == "username":
            assert len(edit_in.value) <= 32, "账号不能超过32个字符"
            assert not await db.fetch_one(
                select(UserModel.id)
                .select_from(UserModel)
                .where(UserModel.username == edit_in.value, UserModel.is_delete == 0)
            ), "当前账号已存在！"

        elif edit_in.field == "realName":
            edit_in.field = "real_name"
            assert len(edit_in.value) <= 32, "真实姓名不能超过32个字符"

        elif edit_in.field == "mobile":
            assert re.match(
                "^[1][3,4,5,6,7,8,9][0-9]{9}$", edit_in.value
            ), "手机号格式不正确"
        elif edit_in.field == "sex":
            if isinstance(edit_in.value, str):
                assert edit_in.value.isdigit(), "性别输入错误"
                edit_in.value = edit_in.value
            assert edit_in.value in SexEnum.key_list(), "性别输入错误"
        else:
            raise AppException(HttpResp.FAILED, msg="不被支持的字段类型")

        edit_dict = {edit_in.field: edit_in.value}

        return await db.execute(
            update(UserModel).where(UserModel.id == edit_in.id).values(**edit_dict)
        )

    async def detail(self, detail_in: UserDetailInSchema) -> UserInfoOutSchema:
        user_record = await db.fetch_one(
            select(UserModel)
            .select_from(UserModel)
            .where(UserModel.id == detail_in.id, UserModel.is_delete == 0)
        )

        assert user_record, "数据不存在！"

        result = UserInfoOutSchema.model_validate(user_record, from_attributes=True)
        result.avatar = await UrlUtil.to_absolute_url(result.avatar)
        result.sex = get_sex(int(result.sex))
        result.channel = get_login_client(int(result.channel))
        return result

    @classmethod
    async def instance(
        cls,
    ):
        """实例化"""
        return cls()
